
package com.jf.cloud.user.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import com.jf.cloud.api.order.constant.OrderStatus;
import com.jf.cloud.api.order.feign.OrderFeignClient;
import com.jf.cloud.api.order.feign.OrderRefundFeignClient;
import com.jf.cloud.api.order.vo.OrderRefundVO;
import com.jf.cloud.api.platform.feign.ConfigFeignClient;
import com.jf.cloud.api.user.bo.UserOrderScoreBo;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.order.bo.EsOrderBO;
import com.jf.cloud.common.order.bo.EsOrderItemBO;
import com.jf.cloud.common.order.constant.OrderCloseType;
import com.jf.cloud.common.order.constant.OrderType;
import com.jf.cloud.common.order.constant.ReturnProcessStatusEnum;
import com.jf.cloud.common.order.vo.OrderItemVO;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.util.Arith;
import com.jf.cloud.common.util.Json;
import com.jf.cloud.common.util.PriceUtil;
import com.jf.cloud.user.constant.*;
import com.jf.cloud.user.mapper.UserExtensionMapper;
import com.jf.cloud.user.model.*;
import com.jf.cloud.user.service.*;
import com.jf.cloud.user.vo.*;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 用户扩展信息
 *
 * @author zz
 * @date 2020-12-08 10:16:53
 */
@Service
public class UserExtensionServiceImpl implements UserExtensionService {

    private static final Logger log = LoggerFactory.getLogger(UserExtensionServiceImpl.class);

    @Autowired
    private UserExtensionMapper userExtensionMapper;
    @Autowired
    private ConfigFeignClient configFeignClient;
    @Autowired
    private OrderFeignClient orderFeignClient;
    @Autowired
    private UserLevelService userLevelService;
    @Autowired
    private OrderRefundFeignClient orderRefundFeignClient;
    @Autowired
    private UserRightsService userRightsService;
    @Autowired
    private UserScoreLogService userScoreLogService;
    @Autowired
    private UserScoreGetLogService userScoreGetLogService;
    @Autowired
    private UserGrowthLogService userGrowthLogService;
    @Autowired
    private UserBalanceLogService userBalanceLogService;


    @Override
    public PageVO<UserExtensionVO> page(PageDTO pageDTO) {
        return PageUtil.doPage(pageDTO, () -> userExtensionMapper.list());
    }

    @Override
    public UserExtension getByUserExtensionId(Long userExtensionId) {
        return userExtensionMapper.getByUserExtensionId(userExtensionId);
    }

    @Override
    public void save(UserExtension userExtension) {
        userExtensionMapper.save(userExtension);
    }

    @Override
    public void update(UserExtension userExtension) {
        userExtensionMapper.update(userExtension);
    }

    @Override
    public void deleteById(Long userExtensionId) {
        userExtensionMapper.deleteById(userExtensionId);
    }

    @Override
    public void updateUserLevel(Integer level, int minGrowth, Integer maxGrowth) {
        userExtensionMapper.updateUserLevel(level, minGrowth, maxGrowth);
    }

    @Override
    public void updateUserScoreOrGrowth(List<Long> userIds, Long score, Integer growth) {
        if (Objects.isNull(score) && Objects.isNull(growth)) {
            return;
        }
        //增加/减少积分或者成长值 , sql中处理积分和成长值不能为负数，最小为0
        userExtensionMapper.updateUserScoreOrGrowth(userIds, score, growth);
    }

    @Override
    public List<UserExtension> getByUserIdsAndLevelType(List<Long> userIds) {
        return userExtensionMapper.getByUserIdsAndLevelType(userIds);
    }

    @Override
    public UserExtension getByUserId(Long userId) {
        return userExtensionMapper.getByUserId(userId);
    }


    @Override
    public int updateBatchUserBalanceByUserIds(List<Long> userIds, Long balance, DateTime now) {
        return userExtensionMapper.updateBatchUserBalanceByUserIds(userIds,balance,now);
    }

    @Override
    public int saveBatch(List<UserExtension> userExtensionList) {
        return userExtensionMapper.saveBatch(userExtensionList);
    }

    @Override
    public void updateScoreAndGrowth(Long orderId) {
        ServerResponseEntity<EsOrderBO> esOrderBoServerResponseEntity = orderFeignClient.getEsOrder(orderId);
        if (!esOrderBoServerResponseEntity.isSuccess()) {
            throw new LuckException(esOrderBoServerResponseEntity.getMsg());
        }
        EsOrderBO esOrderBO = esOrderBoServerResponseEntity.getData();
        //如果订单已经关闭（整单都已经退款了）不需要进行积分、成长值结算
        if (Objects.equals(esOrderBO.getStatus(), OrderStatus.CLOSE.value()) && Objects.equals(esOrderBO.getCloseType(), OrderCloseType.REFUND.value())) {
            return;
        }
        //如果是积分订单不能获取成长值和积分
        if (Objects.equals(esOrderBO.getOrderType(), OrderType.SCORE.value())) {
            return;
        }
        //判断订单是否有订单项退款成功，如果有减少用户可以获取的部分积分
        ServerResponseEntity<List<OrderRefundVO>> orderRefundListServerResponseEntity = orderRefundFeignClient.getOrderRefundByOrderIdAndRefundStatus(esOrderBO.getOrderId(), ReturnProcessStatusEnum.SUCCESS.value());
        if (!orderRefundListServerResponseEntity.isSuccess()) {
            throw new LuckException(orderRefundListServerResponseEntity.getMsg());
        }
        List<OrderRefundVO> orderRefunds = orderRefundListServerResponseEntity.getData();
        List<Long> orderItemIds = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(orderRefunds)) {
            orderRefunds.forEach(refund -> orderItemIds.add(refund.getOrderItemId()));
        }
        // 这里保证了其幂等性
        UserScoreLog orderScoreLog = userScoreLogService.getOrderScoreLog(esOrderBO.getUserId(),esOrderBO.getOrderId(),ScoreLogTypeEnum.SHOP.value(),1);
        if (Objects.nonNull(orderScoreLog)) {
            return;
        }
        // 根据比例取可以获取的积分上限
        List<EsOrderItemBO> products = esOrderBO.getOrderItems();
        // 筛选用户可以获得的订单项积分
        products = products.stream().filter(prodOrderParam -> orderItemIds.stream().noneMatch(
                orderItemId -> Objects.equals(orderItemId, prodOrderParam.getOrderItemId()))).collect(Collectors.toList());
        //获取积分和成长值获取比例
        ServerResponseEntity<String> scoreConfigServerResponseEntity = configFeignClient.getConfig(Constant.SCORE_CONFIG);
        if (!scoreConfigServerResponseEntity.isSuccess()) {
            throw new LuckException(scoreConfigServerResponseEntity.getMsg());
        }
        ScoreCompleteConfigVO scoreParam = Json.parseObject(scoreConfigServerResponseEntity.getData(), ScoreCompleteConfigVO.class);
        ServerResponseEntity<String> growthConfigServerResponseEntity = configFeignClient.getConfig(Constant.GROWTH_CONFIG);
        if (!growthConfigServerResponseEntity.isSuccess()) {
            throw new LuckException(growthConfigServerResponseEntity.getMsg());
        }
        GrowthCompleteConfigVO growthCompleteConfigVO = Json.parseObject(growthConfigServerResponseEntity.getData(), GrowthCompleteConfigVO.class);
        if (Objects.isNull(scoreParam) && Objects.isNull(growthCompleteConfigVO)) {
            return;
        }
        UserExtension userExtension = this.getByUserId(esOrderBO.getUserId());
        //初始每笔订单可以获取的成长值
        double growthPrice = growthCompleteConfigVO.getBuyOrder();
        double getRatioLimit = Objects.isNull(scoreParam) || Objects.isNull(scoreParam.getGetRatioLimit()) ? 0.0 : scoreParam.getGetRatioLimit();
        long totalScore = 0;
        //需要批量修改的orderItem
        List<OrderItemVO> orderItems = new ArrayList<>();
        for (EsOrderItemBO product : products) {
            double scoreLimit;
            double score = Arith.div(product.getActualTotal(), scoreParam.getShoppingGetScore());
            //计算出成长值
            growthPrice += Arith.div(PriceUtil.toDecimalPrice(product.getActualTotal()).doubleValue(), growthCompleteConfigVO.getBuyPrice());
            //判断积分购物获取是全平台还是根据分类上限
            scoreLimit = Arith.div(Arith.mul(esOrderBO.getActualTotal(), getRatioLimit), 100);
            //上限取最小值
            score = Math.min(score, scoreLimit);
            //根据用户等级获取积分倍数
            List<UserRightsVO> userRights = userRightsService.ListRightByLevel(userExtension.getLevel(), userExtension.getLevelType());
            for (UserRightsVO userRightsVO : userRights) {
                if (userRightsVO.getRateScore() != null && userRightsVO.getRateScore() > 1) {
                    score = Arith.div(Arith.mul(score, userRightsVO.getRateScore()), 10);
                }
            }
            long gainScore = (long) score;
            // 如果积分获取开关关闭了，则无法获取积分
            if (Objects.isNull(scoreParam.getShoppingScoreSwitch()) || !scoreParam.getShoppingScoreSwitch()) {
                gainScore = 0;
            }
            if (gainScore <= 0) {
                continue;
            }
            OrderItemVO orderItem = new OrderItemVO();
            orderItem.setOrderItemId(product.getOrderItemId());
            orderItem.setGainScore(gainScore);
            orderItems.add(orderItem);
            totalScore += gainScore;
        }
        checkScoreAndGrowth(esOrderBO, scoreParam, growthCompleteConfigVO, userExtension, growthPrice, totalScore, orderItems);
    }

    private void checkScoreAndGrowth(EsOrderBO esOrderBO, ScoreCompleteConfigVO scoreParam, GrowthCompleteConfigVO growthCompleteConfigVO, UserExtension userExtension, double growthPrice, long totalScore, List<OrderItemVO> orderItems) {
        // 如果积分获取开关关闭了，则无法获取积分
        if (Objects.isNull(scoreParam.getShoppingScoreSwitch()) || !scoreParam.getShoppingScoreSwitch()) {
            totalScore = 0;
        }
        // 如果成长值获取开关关闭了，则无法获取成长值
        if (Objects.isNull(growthCompleteConfigVO.getShopGrowthSwitch()) || !growthCompleteConfigVO.getShopGrowthSwitch()) {
            growthPrice = 0;
        }
        if (CollectionUtils.isNotEmpty(orderItems) && totalScore > 0) {
            orderFeignClient.updateOrderItemBatchById(orderItems);
        }
        // 成长值和积分大于0 增加用户成长值和积分
        if (growthPrice > 0 || totalScore > 0) {
            userLevelService.addGrowthAndScore(growthPrice, totalScore, esOrderBO.getUserId(), esOrderBO.getOrderId(), userExtension, 1);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void refundScore(UserOrderScoreBo userOrderScoreBo) {
        Long orderId = userOrderScoreBo.getOrderId();

        UserScoreGetLog userScoreGetLog = userScoreGetLogService.getLogByBizId(orderId);
        if (Objects.nonNull(userScoreGetLog)) {
            Long completeOrderBack = userScoreGetLog.getUsableScore();
            UserScoreLog userScoreLog2 = new UserScoreLog();
            userScoreLog2.setUserId(userOrderScoreBo.getUserId());
            userScoreLog2.setSource(ScoreLogTypeEnum.COMPLETE_ORDER_BACK.value());
            userScoreLog2.setScore(completeOrderBack);
            userScoreLog2.setBizId(userOrderScoreBo.getRefundId());
            userScoreLog2.setIoType(ScoreIoTypeEnum.EXPENDITURE.value());
            userScoreLogService.save(userScoreLog2);
            userScoreGetLog.setStatus(-1);
            userScoreGetLogService.update(userScoreGetLog);
            userExtensionMapper.updateUserScoreOrGrowth(Collections.singletonList(userOrderScoreBo.getUserId()), -completeOrderBack, null);
        }

        // 如果没有使用积分抵扣就不需要退回积分给用户
        if (Objects.isNull(userOrderScoreBo.getOrderScore()) || Objects.equals(0L, userOrderScoreBo.getOrderScore())) {
            return;
        }

        ServerResponseEntity<EsOrderBO> esOrder = orderFeignClient.getEsOrder(orderId);
        if (!esOrder.isSuccess()) {
            throw new LuckException(esOrder.getMsg());
        }
        Long refundId = userOrderScoreBo.getRefundId();
        ServerResponseEntity<OrderRefundVO> orderRefundResponse = orderRefundFeignClient.getOrderRefundByRefundId(refundId);
        if (!orderRefundResponse.isSuccess()) {
            throw new LuckException(esOrder.getMsg());
        }
        EsOrderBO orderBO = esOrder.getData();
        // 获取退款项
        OrderRefundVO orderRefundVO = orderRefundResponse.getData();
        // 获取退还积分
        Long orderScore;
        if (Objects.equals(1,orderRefundVO.getRefundType())){
            // 整单退款，退款的积分是整个订单的抵扣积分数值
            orderScore = orderBO.getOrderScore();
        } else {
            // 单个退款，退款积分是该订单项下单优惠的积分抵扣数值
            // 单个退款，一定是有orderItemId的
            Long orderItemId = orderRefundVO.getOrderItemId();
            List<EsOrderItemBO> orderItems = orderBO.getOrderItems();
            EsOrderItemBO orderItemVO = orderItems.stream().filter(item -> Objects.equals(item.getOrderItemId(), orderItemId)).findAny().orElse(null);
            orderScore = Objects.isNull(orderItemVO) ? 0L : orderItemVO.getUseScore();
        }
        // 退款退积分比例逻辑：下单选择了积分抵扣，如果订单退款，只退了支付的部分金额，抵扣的积分是退款订单项的抵扣使用积分全部都退回
        if (Objects.isNull(orderScore) || orderScore <= 0L) {
            return;
        }
        Long userId = orderBO.getUserId();
        // 查看是否已有退还记录,如果已经退过积分了，就不用再次退积分了
        // 这里保证了其幂等性
        UserScoreLog orderScoreLog = userScoreLogService.getOrderScoreLog(userId,refundId,ScoreLogTypeEnum.SCORE_CASH_BACK.value(),1);
        if (Objects.nonNull(orderScoreLog)) {
            return;
        }
        UserScoreLog userScoreLog = new UserScoreLog();
        userScoreLog.setUserId(orderBO.getUserId());
        userScoreLog.setSource(ScoreLogTypeEnum.SCORE_CASH_BACK.value());
        userScoreLog.setScore(orderScore);
        userScoreLog.setBizId(refundId);
        userScoreLog.setIoType(ScoreIoTypeEnum.INCOME.value());

        UserScoreGetLog addDetail = new UserScoreGetLog();
        addDetail.setStatus(ScoreGetLogStatusEnum.NORMAL.value());
        addDetail.setUserId(userId);
        addDetail.setUsableScore(orderScore);

        userScoreLogService.save(userScoreLog);
        userScoreGetLogService.save(addDetail);
        userExtensionMapper.updateUserScoreOrGrowth(Collections.singletonList(userId), orderScore,null);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void registerUserScoreGrowthBalanceLog(List<UserExtension> userExtensionList) {
        // 积分、成长值、余额日志
        if (CollUtil.isEmpty(userExtensionList)) {
            return;
        }
        List<UserScoreLog> userScoreLogs = new ArrayList<>();
        List<UserScoreGetLog> userScoreDetails = new ArrayList<>();
        List<UserGrowthLog> userGrowthLogs = new ArrayList<>();
        List<UserBalanceLog> userBalanceLogs = new ArrayList<>();
        for (UserExtension userExtension : userExtensionList) {
            Long userId = userExtension.getUserId();
            Integer growth = userExtension.getGrowth();
            Long score = userExtension.getScore();
            Long balance = userExtension.getBalance();
            // 积分日志
            if (score > 0) {
                UserScoreLog userScoreLog = new UserScoreLog();
                userScoreLog.setUserId(userId);
                userScoreLog.setSource(ScoreLogTypeEnum.SYSTEM.value());
                userScoreLog.setScore(score);
                userScoreLog.setIoType(ScoreIoTypeEnum.INCOME.value());
                userScoreLogs.add(userScoreLog);
                // 积分明细
                UserScoreGetLog userScoreGetLog = new UserScoreGetLog();
                userScoreGetLog.setUserId(userId);
                userScoreGetLog.setUsableScore(score);
                userScoreGetLog.setStatus(ScoreGetLogStatusEnum.NORMAL.value());
                userScoreDetails.add(userScoreGetLog);
            }
            if (growth > 0) {
                // 成长值
                UserGrowthLog userGrowthLog = new UserGrowthLog();
                userGrowthLog.setUserId(userId);
                userGrowthLog.setSource(GrowthLogSourceEnum.SYSTEM.value());
                userGrowthLog.setChangeGrowth(growth);
                userGrowthLog.setRemarks("导入初始化设置成长值");
                userGrowthLogs.add(userGrowthLog);
            }
            if (balance > 0) {
                // 余额日志
                UserBalanceLog userBalanceLog = new UserBalanceLog();
                userBalanceLog.setUserId(userId);
                userBalanceLog.setChangeBalance(balance);
                userBalanceLog.setIoType(RechargeIoTypeEnum.INCOME.value());
                userBalanceLog.setType(RechargeTypeEnum.SYSTEM.value());
                userBalanceLogs.add(userBalanceLog);
            }
        }
        if (CollUtil.isNotEmpty(userScoreLogs)) {
            userScoreLogService.saveBatch(userScoreLogs);
            userScoreGetLogService.saveBatch(userScoreDetails);
        }
        if (CollUtil.isNotEmpty(userGrowthLogs)) {
            userGrowthLogService.saveBatch(userGrowthLogs);
        }
        if (CollUtil.isNotEmpty(userBalanceLogs)) {
            userBalanceLogService.saveBatch(userBalanceLogs);
        }
    }

    @Override
    public void updateByUserRecharge(UserRechargeVO userRechargeVO, UserBalanceLog userBalanceLog) {
        userExtensionMapper.updateByUserRecharge(userRechargeVO, userBalanceLog);
    }

    @Override
    public void addByUserBalanceLog(UserBalanceLog userBalanceLog) {
        userExtensionMapper.addByUserBalanceLog(userBalanceLog);
    }

}
